package com.lujieni.springbootaop.config;
import com.lujieni.springbootaop.dto.ErrorMsg;
import com.lujieni.springbootaop.dto.ResponseDTO;
import com.lujieni.springbootaop.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.ArrayList;
import java.util.List;

/**
 * @Package: com.lujieni.exception.controller
 * @ClassName: BasicController
 * @Author: lujieni
 * @Description: 全局异常处理
 * @Date: 2023-12-11 20:57
 * @Version: 1.0
 *
 * 1.当对应的请求只支持post访问的时候如果你用get来访问那么这里GlobalExceptionController
 *   的handlerException方法会捕获异常并处理
 * 2.当请求已经到了业务代码中,在业务代码中的异常将会由OweExcepetionController的handlerException
 *   方法会捕获异常并处理
 * 3.当HelloController没有继承OweExceptionController的时候所有的异常都将由GlobalExceptionController
 *   来进行处理
 */
@RestControllerAdvice //不加的前提是业务Controller要继承BasicController
public class GlobalExceptionController {

     protected final Logger log = LoggerFactory.getLogger(this.getClass());

     @Autowired
     private MessageSource messageSource; //利用该对象实现对messages520.properties的读取,它是国际化文件

     public GlobalExceptionController() {}

     @ExceptionHandler({Exception.class})
     @ResponseBody
     public ResponseDTO handlerException(Exception exception) {
        this.log.error(exception.getMessage(), exception);
        ResponseDTO responseInfo = new ResponseDTO();
        responseInfo.setSuccess(false);
        if (exception instanceof HttpRequestMethodNotSupportedException) {
            responseInfo.setCode("2");
            responseInfo.setMessage(messageSource.getMessage("method.not.supported.error", null, LocaleContextHolder.getLocale()));
        }else if (exception instanceof MethodArgumentNotValidException) { //校验错误拦截处理
            BindingResult bindingResult = ((MethodArgumentNotValidException)exception).getBindingResult();
            if(bindingResult.hasErrors()){
                // responseInfo.setMessageId((String) bindingResult.getFieldValue("messageId"));
                responseInfo.setCode("4");
                responseInfo.setMessage(messageSource.getMessage("all.data.failed", null, LocaleContextHolder.getLocale()));
                List<ErrorMsg> errors = new ArrayList<>();
                bindingResult.getAllErrors().forEach((fieldError) -> {
                    String defaultMessage = fieldError.getDefaultMessage();
                    if (!StringUtils.isEmpty(defaultMessage) && defaultMessage.contains("{field}")) {
                        if (fieldError.getClass().isAssignableFrom(FieldError.class)) {
                            String field = ((FieldError) fieldError).getField();
                            defaultMessage = defaultMessage.replaceAll("\\{field\\}", field);
                        }
                    }
                    errors.add(getValidateMsgAndCode(defaultMessage));
                });
                responseInfo.setErrors(errors);
            }
        }else if (exception instanceof BusinessException) {
            responseInfo.setCode(((BusinessException) exception).getErrCode());
            responseInfo.setMessage(messageSource.getMessage(((BusinessException) exception).getErrCode(), null, LocaleContextHolder.getLocale()));
        } else {
            //未捕获异常
            responseInfo.setCode("3");
            responseInfo.setMessage(messageSource.getMessage("invoke.system.error", null, LocaleContextHolder.getLocale()));
        }

        return responseInfo;
     }

    /**
     * 取出特定格式异常信息中的errorCode和errorMssage
     *
     * @param errorMessageFormat
     * @return
     * @author DINGYONG
     */
    private ErrorMsg getValidateMsgAndCode(String errorMessageFormat) {
        ErrorMsg errorMsgDto = new ErrorMsg();
        if (StringUtils.isEmpty(errorMessageFormat)){
            return null;
        }

        // code={AvailableLogisticsServiceDTO.packageWidth.notNull.code},message=packageWidth cant't be null

        String [] error = errorMessageFormat.split(",");
        if (error.length == 2) {
            if (error[0].startsWith("code=")) {
                errorMsgDto.setCode(error[0].replaceAll("code=", ""));
            }
            if (error[1].startsWith("message=")) {
                errorMsgDto.setMessage(error[1].replaceAll("message=", ""));
            }
        }else{
            errorMsgDto.setMessage(errorMessageFormat);
        }
        return errorMsgDto;
    }

}